# -*- coding: utf-8 -*-
#fare codice modulare per velocizzare i test

#import
from time import strftime, gmtime
import xml.sax
import sqlite3 as lite
import urllib
from BeautifulSoup import BeautifulSoup
from string import split, join
import os
import gzip
import stat
from urlparse import urlparse

#define
xml_node = "Topic" #nome del nodo xml che ha come valore dell'attributo la categoria dell'url: <Topic r:id="Adult/Arts">
attribute_node = "r:id" #nome dell'attributo che ha come valore la categoria dell'url: <Topic r:id="Adult/Arts">
xml_subnode = "link" #nome del sottonodo di xml_node che ha come valore dell'attributo la url: <link r:resource="http://www.liquidgeneration.com/"/>
attribute_subnode = "r:resource" #nome dell'attributo che ha come valore la url: <link r:resource="http://www.liquidgeneration.com/"/>
print_frequence = 200000 #ogni tot url esaminate per ogni file si effettua una stampa progressiva del totale delle url esaminate
print_download = 10 #ogni tot percentuale scaricata di un file si effettua una stampa progressiva del totale del file scaricato
download_dir = "./tmp/" #directory locale dove salvare i download e dove decomprimerli, se tutto va bene alla fine dell'elaborazione la directory e' vuota
download_page = "http://rdf.dmoz.org/rdf/" #pagina web da cui estrapolare i link
todate = strftime("%Y-%m-%d %H:%M:%S", gmtime()) #stringa della data di attivazione dello script
name_db = "domains_v1.0.db" #nome del db su file
decompression_constant = 6.835 #le dimensioni dei file decompressi aumentano all'incirca di questa costante moltiplicativa, che viene usata nella stampa del progresso dell'unzip del file

#parser
class ABContentHandler(xml.sax.ContentHandler):

    def __init__(self):
        xml.sax.ContentHandler.__init__(self)
       
    def startElement(self, name, attrs):
        global category
        global inserted
        if name == xml_node:
            category = attrs.getValue(attribute_node)
            #print(attrs.getValue(attribute_node)) #stampa di test
        if name == xml_subnode:
            #print(attrs.getValue(attribute_subnode)) #stampa di test
            #print category.replace("/",",") #stampa di test
            elem_url = attrs.getValue(attribute_subnode)
            o = urlparse(elem_url)
            cur.execute("INSERT INTO domains(domain,categoria,data,fonte,reputazione,path) VALUES (?,?,?,?,?,?)",
                        (o.netloc, normalize(category), todate, "_dmoz_", "white list", o.path))
            inserted +=1
            #print category.encode("ascii","ignore") #ignoro i caratteri che non riesco a codificare
            if inserted % print_frequence == 0:
                print inserted, "domini inseriti."
 
           
#funzioni di utilita'
def normalize(s):
#replace from the string s '/' with ',' and '_' with ' '
    return (s.replace("/",",")).replace("_"," ")
           
def get_extension(f):
#returns the extension of a file
    if f.count(".")<=0:
        return False
    f=split(f,".")
    return f[-1]


def get_filename(f):
#returns the filename of a file
    if f.count(".")<=0:
        return f
    a=split(f,".")
    if f.count(".")==1:
        return a[0]
    else:
        return join(a[:-1],".")

def downloadChunks(url,path):
#download large files, the only argument is a url
#this file will go to the given path directory
#the file will be downloaded in chunks and print out how much remains
    file_gz = urllib.urlopen(url)
    total_size = int(file_gz.info().getheader("Content-Length").strip())
    print "Total size ottenuta dall'header Content-Length:", str(total_size), "byte"
    downloaded = 0
    CHUNK = 256 * 10240
    nome_file = os.path.basename(url)
    print "Nome del file da salvare:", nome_file
    #creazione della directory se non esiste
    if not os.path.exists(path):
        os.makedirs(path)
    output = open(path + nome_file,"wb")
    printed_download = 0
    print "Downloading..."
    while True:
        chunk = file_gz.read(CHUNK)
        downloaded += len(chunk)
        progress_download = int((downloaded / float(total_size)) * 100)
        #print "downloaded lenght:", downloaded #stampa di test
        if progress_download % print_download == 0 and not printed_download == progress_download:
            print "Scaricato il", progress_download, "% del file" #stampa di test
            printed_download = progress_download
        if downloaded == total_size:
            output.write(chunk) #pezza: se la prima volta legge di meno, allora rilegge
            break
        if not chunk: break
        output.write(chunk)
    file_gz.close()
    output.close()
    print "Download finito."
    return file

def filesize(n):
#richiede i moduli os e stat
    info = os.stat(n)
    sz = info[stat.ST_SIZE]
    return sz


#sqlite
con = lite.connect(name_db)

with con:
    cur = con.cursor()    
    cur.execute("CREATE TABLE IF NOT EXISTS domains(id INTEGER PRIMARY KEY, domain TEXT, categoria TEXT, data TEXT, fonte TEXT, reputazione TEXT, path TEXT)")

#contenuto html della pagina web
sock = urllib.urlopen(download_page)
htmlSource = sock.read()                            
sock.close()                                        
#print htmlSource #stampa di test

#estrazione dei link .gz dall'html
soup = BeautifulSoup(htmlSource)
for tag in soup.findAll("a", href=True):
    #print tag["href"] #stampa di test
    #print get_extension(tag["href"]) #stampa di test
    if get_extension(tag["href"]) == "gz":
        #print download_page + tag["href"] #stampa di test
        #estrazione dei soli link che contengono content nel nome
        if tag["href"].endswith("content.rdf.u8.gz") and tag["href"].find("aol") != 0 :
            #si evita di scaricare aol perche' non contiene niente
            print "Url del file .gz da scaricare:", download_page + tag["href"] #stampa di test

            #download dei file
            #scarica solo i file content che sono quelli che contengono le url
            downloadChunks(download_page + tag["href"], download_dir)

            #apertura file .gz
            f = gzip.open(download_dir + tag["href"], "rb")
            #eliminazioe di .gz dal nome del file
            xml_name_file = get_filename(tag["href"]) + ".xml"
            xml_file = open(download_dir + xml_name_file,"wb")
            file_size = filesize(download_dir + tag["href"])
            print "Dimensione del file .gz scaricato:", file_size, "byte"

            #unzip del file
            downloaded = 0
            CHUNK = 256 * 10240
            printed_copy = 0
            print "Unzip..."
            while True:
                chunk = f.read(CHUNK)
                downloaded += len(chunk)
                if not chunk: break
                chunk = chunk.replace("&#3;","")
                xml_file.write(chunk.replace("&#28;", ""))#pezza, dava fatal error nella decodifica del file xml causata da questo carattere
                progress_copy = int((downloaded / float(file_size)) * 100 / decompression_constant)
                #print progress_copy #stampa di test
                if progress_copy % 10 == 0 and not printed_copy == progress_copy:
                    print "Unzippato il", progress_copy, "% del file"
                    printed_copy = progress_copy

            f.close()
            xml_file.close()
            print "Unzip finito."
            file_size_unzipped = filesize(download_dir + xml_name_file)
            print "Dimensione del file xml scaricato:", file_size_unzipped, "byte"

            #unlink file gz
            os.remove(download_dir + tag["href"])
           
            #parsing
            inserted = 0
            source = open(download_dir + xml_name_file)
            xml.sax.parse(source, ABContentHandler())
            print "Elaborazione file terminata:", inserted, "domini inseriti."

            #eliminazione file estratto
            os.remove(download_dir + xml_name_file)
            print "------------------------------------------------------------------------"
            con.commit()

#con.commit()
con.close()  
